import configs from "./config";
import MgobeData from "./MgobeData";
import { calcFrame, clearFrames, pushFrames } from "./logic/FrameSyncLogic";
import { setState } from "./logic/StateSyncLogic";
import config from "./config";

export default class MgobeManager {
    /**
     * 初始化 MGOBE SDK
     * @param gameInfo 
     * @param config 
     * @param callback 
     */
    public static initSDK(gameId: string, secretKey: string, url: string, cacertNativeUrl: string, callback?: (event: { code: MGOBE.ErrCode }) => any): void {

        // 如果已经初始化，直接回调成功
        if (this.isInited()) {
            return callback && callback({ code: MGOBE.ErrCode.EC_OK });
        }

        const defaultGameInfo: MGOBE.types.GameInfoPara = {
            gameId: configs.gameId,
            openId: configs.openId,
            secretKey: configs.secretKey,
        };

        const defaultConfig: MGOBE.types.ConfigPara = {
            url: configs.url,
            isAutoRequestFrame: true,
            cacertNativeUrl: "",
        };

        Object.assign(defaultGameInfo, { gameId, secretKey });
        Object.assign(defaultConfig, { url, cacertNativeUrl });

        MGOBE.DebuggerLog.enable = config.debugger;

        // 初始化
        MGOBE.Listener.init(defaultGameInfo, defaultConfig, event => {
            if (event.code === MGOBE.ErrCode.EC_OK) {
                MgobeData.room = new MGOBE.Room();
                MgobeData.gameId = defaultGameInfo.gameId;

                MGOBE.Listener.add(MgobeData.room);
                // 设置默认广播
                // this.setBroadcastCallbacks(MgobeData.room, null, {});
                this.setBroadcastCallbacks(MgobeData.room, MgobeManager, MgobeManager);
                // MgobeData.room.onJoinRoom = this.onJoinRoom;
            }

            callback && callback({ code: event.code });
        });
    }

    /**
     * 判断 MGOBE SDK 是否初始化完成
     */
    public static isInited(): boolean {
        // 初始化成功后才有玩家ID
        return !!MGOBE.Player && !!MGOBE.Player.id;
    }

    /**
     * 设置房间广播回调函数
     * @param broadcastCallbacks 
     */
    public static setBroadcastCallbacks(room: MGOBE.Room, context: any, broadcastCallbacks?: BroadcastCallbacks) {

        if (!room) {
            return;
        }

        // 默认回调函数
        const generateDefaultCallback = (tag: string) => (event) => null;

        const defaultCallbacks: BroadcastCallbacks = {
            onJoinRoom: () => generateDefaultCallback("onJoinRoom"),
            onLeaveRoom: () => generateDefaultCallback("onLeaveRoom"),
            onChangeRoom: () => generateDefaultCallback("onChangeRoom"),
            onDismissRoom: () => generateDefaultCallback("onDismissRoom"),
            onStartFrameSync: () => generateDefaultCallback("onStartFrameSync"),
            onStopFrameSync: () => generateDefaultCallback("onStopFrameSync"),
            onRecvFrame: (event: MGOBE.types.BroadcastEvent<MGOBE.types.RecvFrameBst>) => {
                generateDefaultCallback("onRecvFrame");
                // 每次收到帧广播都需要计算
                calcFrame(event.data.frame);
            },
            onChangeCustomPlayerStatus: () => generateDefaultCallback("onChangeCustomPlayerStatus"),
            onRemovePlayer: () => generateDefaultCallback("onRemovePlayer"),
            onRecvFromClient: () => generateDefaultCallback("onRecvFromClient"),
            onRecvFromGameSvr: () => generateDefaultCallback("onRecvFromGameSvr"),
            onAutoRequestFrameError: () => generateDefaultCallback("onAutoRequestFrameError"),
        };

        // 给 room 实例设置广播回调函数
        Object.keys(defaultCallbacks).forEach((key: keyof BroadcastCallbacks) => {
            const callback = broadcastCallbacks[key] ? broadcastCallbacks[key].bind(context) : defaultCallbacks[key];
            room[key] = callback;
        });
    }

    /**
     * 创建房间
     */
    public static createRoom() {
        const playerInfo: MGOBE.types.PlayerInfoPara = {
            name: config.openId,
            customPlayerStatus: 0,
            customProfile: "",
        };

        const createRoomPara: MGOBE.types.CreateRoomPara = {
            roomName: "cocos_demo",
            roomType: "create",
            maxPlayers: 5,
            isPrivate: true,
            customProperties: "",
            playerInfo,
        };

        MgobeData.room.initRoom();
        MgobeData.room.createRoom(createRoomPara, event => {
            if (event.code === MGOBE.ErrCode.EC_OK) {
                console.log(`创建房间成功，房间ID：${event.data.roomInfo.id},`, event.data.roomInfo.id);
            } else {
                console.log(`创建房间失败，错误码：${event.code}`);
            }
        });
    }

    /**
     * 加入房间
     * @param roomId 房间ID
     */
    public static joinRoom(roomId) {
        if (!roomId) {
            return console.log(`请输入正确的房间ID`);
        }

        console.log(`正在加入房间，房间ID：${roomId}`);

        const playerInfo: MGOBE.types.PlayerInfoPara = {
            name: config.openId,
            customPlayerStatus: 0,
            customProfile: "",
        };

        const joinRoomPara: MGOBE.types.JoinRoomPara = {
            playerInfo,
        };

        MgobeData.room.initRoom({ id: roomId });
        MgobeData.room.joinRoom(joinRoomPara, event => {
            if (event.code === MGOBE.ErrCode.EC_OK) {
                console.log(`加入房间成功，房间ID：${event.data.roomInfo.id}`);
                // this.loadRoomScene();
            } else {
                console.error(`加入房间失败，${event.code === MGOBE.ErrCode.EC_ROOM_TEAM_MEMBER_LIMIT_EXCEED ? "当前房间玩家数量已满，" : ""}错误码：${event.code}`);
            }
        });
    }

    /**
     * 随机匹配
     * @param matchCode 
     */
    private static timer;
    public static matchRoom(matchCode: string) {

        this.timer = setInterval(() => console.log(`正在随机匹配，请稍等。`), 1000);
        console.log(`正在随机匹配，匹配Code：${matchCode}。请稍等。`);

        // 注意：这里没有使用匹配属性，如果匹配规则中有设置匹配属性，这里需要做调整
        const matchAttributes: MGOBE.types.MatchAttribute[] = [];

        const playerInfo: MGOBE.types.MatchPlayerInfoPara = {
            name: config.openId,
            customPlayerStatus: 0,
            customProfile: "",
            matchAttributes,
        };

        const matchPlayersPara: MGOBE.types.MatchPlayersPara = {
            matchCode,
            playerInfo,
        };

        MgobeData.room.initRoom();
        MgobeData.room.matchPlayers(matchPlayersPara, event => {
            clearInterval(this.timer);
            if (event.code === MGOBE.ErrCode.EC_OK) {
                console.log(`随机匹配成功，房间ID：${event.data.roomInfo.id},`, event);
            } else {
                console.log(`随机匹配失败，错误码：${event.code}`);
            }
        });
    }

    // SDK 退出房间
    public static leaveRoom() {
        console.log(`正在退出房间`);

        MgobeData.room.leaveRoom({}, event => {
            if (event.code === MGOBE.ErrCode.EC_OK) {
                console.log(`退出房间成功`);
            } else {
                console.log(`退出房间失败，错误码：${event.code}`);
            }
        });
    }

    // SDK 玩家进房广播
    public static onJoinRoom(event: MGOBE.types.BroadcastEvent<MGOBE.types.JoinRoomBst>) {
        console.error(`广播：玩家进房${event},`, event);
    }

    // SDK 玩家退房广播
    public static onLeaveRoom(event: MGOBE.types.BroadcastEvent<MGOBE.types.LeaveRoomBst>) {
        console.error(`广播：玩家退房${event}`, event);
    }

    // SDK 房间解散广播
    public static onDismissRoom(event: MGOBE.types.BroadcastEvent<MGOBE.types.DismissRoomBst>) {
        console.log(`广播：房间解散`);
        return cc.director.loadScene("mgobe");
    }

    // SDK 开始帧同步
    public static onStartFrame() {
        clearFrames();
    }

    // SDK 停止帧同步
    public static onStopFrame() {
        clearFrames();
    }

    // SDK 房间内消息广播
    public static onRecvFromClient(event: MGOBE.types.BroadcastEvent<MGOBE.types.RecvFromClientBst>) {
        // this.uiChat.appendMsg(event.data.msg, event.data.sendPlayerId === MGOBE.Player.id);
    }

    // SDK 实时服务器广播
    public static onRecvFromGameSvr(event: MGOBE.types.BroadcastEvent<MGOBE.types.RecvFromGameSvrBst>) {
        setState(event.data && event.data.data && event.data.data["players"]);
    }

    // SDK 帧同步广播
    public static onRecvFrame(event: MGOBE.types.BroadcastEvent<MGOBE.types.RecvFrameBst>) {
        pushFrames(event.data.frame);
        calcFrame(event.data.frame);
    }


}

